#include "scrolledfitsview.h"

ScrolledFitsView::ScrolledFitsView(QWidget*){
	setBackgroundRole(QPalette::Dark);
	fitsView = new FitsView(this);
	setWidget(fitsView);
	zoom = -1; // maximum fitting in window
}

ScrolledFitsView::~ScrolledFitsView(){
	delete fitsView;
}


/// pass through slot, could be signal
void ScrolledFitsView::setFits(FITS *fits){
	fitsView->setFits(fits);
}
/// pass through slot, could be signal
void ScrolledFitsView::setColormap(const unsigned *map){
	fitsView->setColormap(map);
}
/// pass through slot, could be signal
void ScrolledFitsView::setGray(double midValue, double grayScale){
	fitsView->setGray(midValue, grayScale);
}

/**
 * wrapper for setZoom(double) with integer arguments
 * @param zoomi 100 times zoom.
 */
void ScrolledFitsView::setZoomi(int zoom){
	setZoom(0.01*zoom);
}

/**
 * slot
 * @param zoom Negative zooms are relative to window size, positive are relative to true size.
 *
 */
void ScrolledFitsView::setZoom(double zoom){
	printf("setzoom %f\n", zoom);
	this->zoom = zoom;
	QSize imSize = fitsView->sizeHint(); // natural size
	if(zoom>0) // relative to true image size
		fitsView->resize(zoom*imSize);
	else { // relative to window size
		imSize.scale(-zoom*maximumViewportSize(), Qt::KeepAspectRatio); // max aspect
		fitsView->resize(imSize);
	}
}

/** wrapper for setZoom(double) with integer arguments
  */
void ScrolledFitsView::multZoomi(int zoomFactor){
	multZoom(0.01*zoomFactor);
}

/** multiply zoom with certain factor. Sign is conserved.
  */
void ScrolledFitsView::multZoom(double zoomFactor){
	setZoom(this->zoom *= zoomFactor);
}

/** Alter te rotation with a certain number of degrees.
  * For setting absolute, use setRotation
  */
void ScrolledFitsView::rotate(int angle){
	//QPoint scrollBarPos = QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
	//QPoint imPos = scrollBarPos + .5*maximumViewportSize();
	fitsView->setRotation(((int)fitsView->getRotation()+angle));
}

QSize ScrolledFitsView::minimumSizeHint() const{
	return QSize(50, 50);
}

/** cap x to the range a-b
  */
static double range(double x, double a, double b){
	return x<a?a:x>b?b:x;
}

void ScrolledFitsView::resizeEvent(QResizeEvent *event){
}

/**
 * handle a wheelevent if ctrl is pressed for zooming
 * pass it to base class otherwise
 */
void ScrolledFitsView::wheelEvent(QWheelEvent *event){
	double scale = 1.1;
	double maxZoom = 2;
	// normalized position relative to image
	if(event->modifiers()==Qt::ControlModifier){ // if control pressed
		QSize imSize = fitsView->sizeHint(); // natural size
		// position of mouse in image
		QPoint scrollBarPos = QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
		QPoint imPos = event->pos()+scrollBarPos;
		fitsView->setSuspendDraw(true);
		fitsView->setUpdatesEnabled(false);
		if(event->delta()>0){ // zoom in
			if(fitsView->width()>maxZoom*imSize.width() || fitsView->height()>maxZoom*imSize.height())
				return;
			imPos *= scale; // position of mouse in scaled image
			scrollBarPos = imPos - event->pos();// todo: must be more if scrollbar just appeared in next line
			fitsView->resize(fitsView->size()*scale);
		} else { // zoom out
			// if image would become smaller than maximum viewportsize
			if(maximumViewportSize().width()>fitsView->width()/scale &&
			   maximumViewportSize().height()>fitsView->height()/scale){
				scale = max((double)fitsView->width() / maximumViewportSize().width(),
					(double)fitsView->height() / maximumViewportSize().height());
			}
			imPos /= scale; // position of mouse in scaled image
			scrollBarPos = imPos - event->pos();
			fitsView->resize(fitsView->size()/scale);
		}
		horizontalScrollBar()->setValue(scrollBarPos.x());
		verticalScrollBar()->setValue(scrollBarPos.y());
		fitsView->setSuspendDraw(false);
		fitsView->setUpdatesEnabled(true);
	} else
		QScrollArea::wheelEvent(event); // propagate to base class
}


/** handle mouse events for contrast adjustments:
  *   right click, right drag, ctrl left click, ctrl left drag
  */
void ScrolledFitsView::mouseEvent(QMouseEvent *event){
	double xPos = range((double)event->x()/viewport()->width(), 0, 1); // [0-1]
	double yPos = range((double)event->y()/viewport()->height(), 0, 1); // [0-1] bottom=1
	// central value (which maps to the center gray)
	double midValue = pow(xPos, 3);
	double grayScale = (yPos-.5)*100; // d gray/ d value
	//printf("pos(%5.3f-%5.3f), midValue: %5.3f, grayScale: %8.3f\n",	xPos, yPos, midValue, grayScale);
	fitsView->setGray(midValue, grayScale);
	emit grayChanged(midValue, grayScale); // let the world know what we did
}

/** send mouse presses to mouseEvent()
  */
void ScrolledFitsView::mousePressEvent(QMouseEvent *event){
	if(event->buttons() & Qt::RightButton ||
	   (event->buttons() & Qt::LeftButton && event->modifiers()==Qt::ControlModifier))
		mouseEvent(event);
	else
		QScrollArea::mousePressEvent(event);
}

/** send mouse drags to mouseEvent()
  */
void ScrolledFitsView::mouseMoveEvent(QMouseEvent *event){
	if(event->buttons() & Qt::RightButton ||
	   (event->buttons() & Qt::LeftButton && event->modifiers()==Qt::ControlModifier))
		mouseEvent(event);
	else
		QScrollArea::mouseMoveEvent(event);
}
